//
//  ClipService.swift
//  zcliperd
//
//  Created by 张宇飞的电脑 on 2019/9/5.
//

import Foundation
import Socket
import Dispatch

class ClipService {
    static let READ_BUF_SIZE = 4096
    static let CMD_LIST = "list"  // 列出粘贴板
    static let CMD_CLEAR = "clear"  // 清空粘贴板
    static let CMD_SET = "set"  // 设置粘贴板
    private var pb: Clipboard? = nil
    private var bufSize: Int
    private var buf: [String]

    private var sockPath: String
    private var listenSock: Socket? = nil

    private var running = true

    init(_ sockPath: String,_ bufSize: Int) {
        self.bufSize = bufSize
        self.buf = []
        self.sockPath = sockPath
        // 启动粘贴板监听
        startListenClipboard()
    }

    func run() {
        let queue = DispatchQueue.global(qos: .userInteractive)
        queue.async { [unowned self] in

            do {
                // 打开文件，启动监听
                try self.listenSock = Socket.create(family: .unix, type: .stream, proto: .unix)
                guard let socket = self.listenSock else {
                    print("unable to unwrap socket...")
                    return
                }
                socket.readBufferSize = ClipService.READ_BUF_SIZE
                try socket.listen(on: self.sockPath)
                print("listening on sock: \(self.sockPath)")

                repeat {
                    let newSocket = try socket.acceptClientConnection()
                    self.handleConnection(newSocket)
                } while self.running
            } catch let error {
                guard let socketError = error as? Socket.Error else {
                    print("Unexpected error...")
                    return
                }

                if self.running {
                    print("Error reported:\n \(socketError.description)")
                }
            }
        }

        RunLoop.main.run()
    }

    func handleConnection(_ socket: Socket) {
        let queue = DispatchQueue.global(qos: .default)
        queue.async { [unowned self, socket] in
            do {
                var readData = Data(capacity: ClipService.READ_BUF_SIZE)
                _ = try socket.read(into: &readData)

                let cmdData = String(data: readData, encoding: .utf8) ?? ""
                var data: Any
                var cmd: String

                if cmdData.hasPrefix(ClipService.CMD_LIST) {
                    data = self.buf
                    cmd = ClipService.CMD_LIST
                } else if cmdData.hasPrefix(ClipService.CMD_CLEAR) {
                    DispatchQueue.main.sync {
                        [unowned self] in
                        self.buf.removeAll()
                    }
                    cmd = ClipService.CMD_CLEAR
                    data = "ok"
                }
//                else if cmdData.hasPrefix(ClipService.CMD_SET) {
//                    cmd = ClipService.CMD_SET
//                    let startIdx = cmd.count + 1
//                    if cmdData.count <= startIdx {
//                        data = "fail"
//                    } else {
//                        data = "ok"
//                        let idx = cmdData.index(cmdData.startIndex, offsetBy: startIdx)
//                        let setData = String(cmdData[idx...])
//                        DispatchQueue.main.sync {
//                            [unowned self, setData] in
//                            self.pb?.copy(setData)
//                        }
//                    }
//                }
                else {
                    data = "invalid cmd"
                    cmd = cmdData.trimmingCharacters(in: .whitespacesAndNewlines)
                }
                let jdata = try JSONSerialization.data(withJSONObject: ["cmd": cmd, "data": data], options: [])
                let sizeStr = String(jdata.count)
                try socket.write(from: sizeStr)
                try socket.write(from: jdata)

                print("a socket closed...")
                socket.close()

            } catch let error {
                guard let socketError = error as? Socket.Error else {
                    print("Unexpected error...")
                    return
                }
                if self.running {
                    print("Error reported:\n \(socketError.description)")
                }
            }

        }
    }

    func stop() {
        print("stop daemon")
        self.running = false
        pb?.stopListening()
        listenSock?.close()
        exit(0)
    }

    private func startListenClipboard() {
        pb = Clipboard()

        pb?.onNewCopy {[unowned self](content)  in
            // 判断 conetent 是否已经存在了。如果存在就不保存
            if self.buf.count > 0 {
                var existIdx = -1
                for i in 0...self.buf.count-1 {
                    let c = self.buf[i]
                    if c.count == content.count && c == content {
                        existIdx = i
                        break
                    }
                }

                if existIdx >= 0 {
                    let lastIdx = self.buf.count - 1
                    if lastIdx != existIdx {
                        (self.buf[existIdx], self.buf[lastIdx]) = (self.buf[lastIdx], content)
                    }
                    return
                }
            }
            // 清除超过历史记录条数上限的数据
            while self.buf.count >= self.bufSize {
                self.buf.removeFirst()
            }
            self.buf.append(content)
        }
        pb?.startListening()
    }
}
